package com.strato.file.remote.v1_0_0.client;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import com.strato.annotation.osgi.v1_0_0.service.OsgiService;
import com.strato.base.env.v1_0_0.GlobalEnvironment;
import com.strato.file.api.v1_0_0.FileService;
import com.strato.logging.v1_0_0.api.Log;
import com.strato.logging.v1_0_0.api.LogFactory;

@OsgiService(id="remoteFileService")
public class RemoteFileService implements FileService {

	private Log log=LogFactory.getLog(getClass());
	
	private String baseUrl="${strato.file.remote.baseurl}";
	
	private String viewUrl="${strato.file.remote.viewurl}";
	
	public void setBaseUrl(String baseUrl) {
		this.baseUrl = baseUrl;
	}
	
	public void setViewUrl(String viewUrl) {
		this.viewUrl = viewUrl;
	}

	@Override
	public void save(InputStream input, String targetPath) throws IOException {
		CloseableHttpClient httpclient = getHttpClient();
		CloseableHttpResponse response=null;
		try{
			String url=GlobalEnvironment.getInstance().resolveString(baseUrl)+"/put?path="+targetPath;
			HttpPost post=new HttpPost(url);
			post.setConfig(this.getRequestConfig());
			HttpEntity entity = EntityBuilder.create().setStream(input).build();
			post.setEntity(entity);
			response = httpclient.execute(post);
			if(response.getStatusLine().getStatusCode()!=200){
				log.error(response.getStatusLine().getReasonPhrase());
				throw new RuntimeException(response.getStatusLine().getReasonPhrase());
			}
		}finally{
			if(response!=null){
				try{
					response.close();
				}catch(Exception e){};
			}
			httpclient.close();
		}
	}

	@Override
	public void copy(String sourcePath, String targetPath) throws IOException {
		CloseableHttpClient httpclient = getHttpClient();
		CloseableHttpResponse response=null;
		try{
			String url=GlobalEnvironment.getInstance().resolveString(baseUrl)+"/copy";
			HttpGet get=new HttpGet(url);
			get.setConfig(this.getRequestConfig());
			response = httpclient.execute(get);
			if(response.getStatusLine().getStatusCode()!=200){
				log.error(response.getStatusLine().getReasonPhrase());
				throw new RuntimeException(response.getStatusLine().getReasonPhrase());
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(response!=null){
				try{
					response.close();
				}catch(Exception e){};
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
	}

	@Override
	public void delete(String filepath) {
		CloseableHttpClient httpclient = getHttpClient();
		CloseableHttpResponse response=null;
		try{
			String url=GlobalEnvironment.getInstance().resolveString(baseUrl)+"/delete?path="+filepath;
			HttpGet get=new HttpGet(url);
			get.setConfig(this.getRequestConfig());
			response = httpclient.execute(get);
			if(response.getStatusLine().getStatusCode()!=200){
				log.error(response.getStatusLine().getReasonPhrase());
				throw new RuntimeException(response.getStatusLine().getReasonPhrase());
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(response!=null){
				try{
					response.close();
				}catch(Exception e){};
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
	}

	@Override
	public void load(String sourcePath, OutputStream output) throws IOException {
		CloseableHttpClient httpclient = getHttpClient();
		CloseableHttpResponse response=null;
		try{
			String url=GlobalEnvironment.getInstance().resolveString(baseUrl)+"/get?path="+sourcePath;
			HttpGet get=new HttpGet(url);
			get.setConfig(this.getRequestConfig());
			response = httpclient.execute(get);
			if(response.getStatusLine().getStatusCode()!=200){
				log.error(response.getStatusLine().getReasonPhrase());
				throw new RuntimeException(response.getStatusLine().getReasonPhrase());
			}
			InputStream input = new BufferedInputStream(response.getEntity().getContent());
			BufferedOutputStream out = new BufferedOutputStream(output);
			IOUtils.copy(input, out);
			out.flush();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(response!=null){
				try{
					response.close();
				}catch(Exception e){};
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
	}

	@Override
	public boolean exists(String path) throws IOException {
		CloseableHttpClient httpclient = getHttpClient();
		CloseableHttpResponse response=null;
		try{
			String url=GlobalEnvironment.getInstance().resolveString(baseUrl)+"/exists?path="+path;
			HttpGet get=new HttpGet(url);
			get.setConfig(this.getRequestConfig());
			response = httpclient.execute(get);
			if(response.getStatusLine().getStatusCode()!=200){
				log.error(response.getStatusLine().getReasonPhrase());
				throw new RuntimeException(response.getStatusLine().getReasonPhrase());
			}
			InputStream content = response.getEntity().getContent();
			String result=IOUtils.toString(content);
			return Boolean.parseBoolean(result);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}finally{
			if(response!=null){
				try{
					response.close();
				}catch(Exception e){};
			}
			try {
				httpclient.close();
			} catch (IOException e) {
			}
		}
	}

	private CloseableHttpClient getHttpClient(){
		CloseableHttpClient httpclient = HttpClients.createDefault();
		return httpclient;
	}
	
	private final int DEFAULT_SO_TIMEOUT = 60000;
	
	private final int DEFAULT_CONNECTION_TIMEOUT = 10000;
	
	private RequestConfig getRequestConfig(){
		
		Integer socketTimeOut = GlobalEnvironment.getInstance().resolveInteger("${strato.file.remote.socketTimeout}");
		if(socketTimeOut == null){
			socketTimeOut = DEFAULT_SO_TIMEOUT;
		}
		
		Integer connectTimeOut = GlobalEnvironment.getInstance().resolveInteger("${strato.file.remote.connectTimeout}");
		if(connectTimeOut == null){
			connectTimeOut = DEFAULT_CONNECTION_TIMEOUT;
		}
		RequestConfig requestConfig = RequestConfig.custom()
		.setSocketTimeout(socketTimeOut)
		.setConnectTimeout(connectTimeOut)
        .build();
		return requestConfig;
	}

	@Override
	public String getViewUrl(String path) {
		return  GlobalEnvironment.getInstance().resolveString(viewUrl)+"/"+path;
	}
}
